/*
 * Skin.cpp
 *
 *  Created on: 2012/03/16
 *      Author: takedanaoki
 */

#include "StdAfx.h"
#include "NTEngine/NTEngine.h"
#include "NTEngine/Base/RefString.h"
#include "NTEngine/Xml/Element.h"
#include "NTEngine/Xml/Attribute.h"

#include "Scene/src/Node.h"
#include "Scene/src/Skin.h"
#include "Scene/src/SkinNode.h"
#include "Scene/src/ContainerImpl.h"

namespace NTEngine {
using namespace Xml;
namespace Scene {

Skin::Skin( Xml::ConstElement& e, Container::Impl& c )
: mMaxWeightsPerVertex( 0 )
, mWeights( 0 )
, mMatrixIndeices( 0 )
, mBoneNumber( 0 )
, mBones( 0 )
, mNodeNumber ( 0 )
, mNodes( 0 )
, mName( 0 )
, mBuffer( 0 )
, mContainer( &c ) {
	ASSERT( RefString( "Skin" ) == e.name() ); //Skinだよね？
	ASSERT( e.childNumber() > 0 ); //ノード一個はあるよね？
	//名前取得
	int an = e.attributeNumber();
	for ( int i = 0; i < an; ++i ){
		ConstAttribute a = e.attribute( i );
		RefString name( a.name() );
		if ( name == "name" ){
			mName = c.allocateString( RefString( a.value() ) );
		} else if ( name == "maxWeights" ) {
			mMaxWeightsPerVertex = a.getIntValue();
		} else if ( name == "vertexBuffer" ) {
			mVertexBuffer = c.vertexBuffer( a.value() );
			ASSERT( mVertexBuffer && "Skin : VertexBuffer not found!" );
			ASSERT( mVertexBuffer.managed() == VertexBuffer::MANAGED_DYNAMIC ); // 動的バッファだよな？
			// バッファ初期データコピー
			mBuffer = NEW Graphics::Vertex[ mVertexBuffer.vertexNumber() ];
			Vertex* buf;
			mVertexBuffer.lock( &buf );
			for ( int i = 0; i < mVertexBuffer.vertexNumber(); ++i ) {
				mBuffer[ i ] = buf[ i ];
			}
			mVertexBuffer.unlock( &buf );
		} else if ( name == "boneNumber" ) {
			mBoneNumber = a.getIntValue();
			ASSERT( mBoneNumber );
			mBones = NEW Matrix3x4[ mBoneNumber ];
		}
	}
	// ノードごとに取得
	mNodeNumber = e.childNumber();
	mNodes = static_cast< SkinNode* >( OPERATOR_NEW( sizeof( SkinNode ) * mNodeNumber ) );
	mNodeMap.setCapacity( mNodeNumber );
	for ( int i = 0; i < mNodeNumber; ++i ) {
		ConstElement child = e.child( i );
		new ( &mNodes[ i ] ) SkinNode( child, c, mBones );
		mNodeMap.add( mNodes[ i ].name(), i );
	}
	// 頂点用の変換データ準備
	int num = mVertexBuffer.vertexNumber() * mMaxWeightsPerVertex;
	mWeights = NEW float[ num ];
	mMatrixIndeices = NEW int[ num ];
	for ( int i = 0; i < num; ++ i ) {
		mWeights[ i ] = 0;
		mMatrixIndeices[ i ] = -1;
	}
}

void Skin::generate( Node* bone ) {
	SkinNode* skin = 0;
	int p = mNodeMap.find( bone->name() );
	if ( !mNodeMap.isEnd( p ) ){
		int idx = *mNodeMap.value( p );
		skin = &mNodes[ idx ];
	}
	if ( skin == 0 ) {
		return;
	}
	skin->setOffset( bone->offset() );
	int matrixIndex = bone->id();
	bone->setSkin( skin );
	int n = skin->weightNumber();
	for ( int i = 0; i < n; ++i ) {
		int idx = skin->vertexIndex( i ) * mMaxWeightsPerVertex;
int cnt = 0;
		for ( int k = 0; k < mMaxWeightsPerVertex; ++k ) {
			// 既にはいっていないかチェック
			if ( mMatrixIndeices[ idx ] < 0 ) {
				break;
			}
++cnt;
			++idx;
		}
		ASSERT( cnt < mMaxWeightsPerVertex ); // MAXよりおおいじゃねぇか。ファイルを見直してくれ
		mMatrixIndeices[ idx ] = matrixIndex;
		mWeights[ idx ] = skin->weights( i );
	}
	skin->deleteWeights();
}

} // namespace Scene
} // namespace NTEngine
